package com.eurobcoin.invite;

import java.text.MessageFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import org.apache.ibatis.session.SqlSession;

import com.eurobcoin.dao.mapper.InvitesSentMapper;
import com.eurobcoin.dao.mapper.UserToUserMapper;
import com.eurobcoin.dao.mapper.UsersInviteCountMapper;
import com.eurobcoin.dao.model.InvitesSent;
import com.eurobcoin.dao.model.InvitesSentExample;
import com.eurobcoin.dao.model.UserToUser;
import com.eurobcoin.dao.model.UsersInviteCount;
import com.eurobcoin.dao.model.UsersInviteCountExample;
import com.eurobcoin.helper.PasswdHelper;
import com.eurobcoin.helper.TextsHelper;

public class InviteManager {

	public static final Long INVITE_EXPIRATION_MS = 72L * 60L * 60L * 1000L;
	
	public int getInvitingUserByHash(SqlSession sqlSession, String inviteHash) {
		
		int ret = 0;
		
		InvitesSentMapper mapper = sqlSession.getMapper(InvitesSentMapper.class);
		InvitesSentExample example = new InvitesSentExample();
		InvitesSentExample.Criteria criteria = example.createCriteria();
		criteria.andIvs_hashEqualTo(inviteHash);
		
		List<InvitesSent> invitesList = mapper.selectByExample(example);
		
		if(invitesList.size() > 0)
			ret = invitesList.get(0).getUsr_id();
		
		return ret;
		
	}
	
	public boolean isValidInvite(SqlSession sqlSession, String inviteHash) {
		
		boolean ret = false;
		
		InvitesSentMapper mapper = sqlSession.getMapper(InvitesSentMapper.class);
		InvitesSentExample example = new InvitesSentExample();
		InvitesSentExample.Criteria criteria = example.createCriteria();
		criteria.andIvs_hashEqualTo(inviteHash);
		
		List<InvitesSent> invitesList = mapper.selectByExample(example);
		InvitesSent invitesSent = null;
		
		if(invitesList.size() > 0)
			invitesSent = invitesList.get(0);
		
		if(invitesSent != null) {
			
			long inviteTimestamp = invitesSent.getIvs_date().getTime();
			long inviteValidUntil = inviteTimestamp + INVITE_EXPIRATION_MS;
			
			long now = System.currentTimeMillis();
			
			if(now < inviteValidUntil) {
				// OK
				ret = true;
			} 
			
		}
		
		return ret;
		
	}
	
	public InviteSendResponse sendInvitation(
			SqlSession sqlSession,
			Locale userLocale,
			int invitingUser,
			String invitingUsername,
			String email) throws Exception {
		
		InviteSendResponse ret = new InviteSendResponse();
		
		// 1. comprobar que tiene invitaciones suficientes
		int availableInvites = this.countInvitesForUser(sqlSession, invitingUser);
		if(availableInvites < 1) {
			ret.setResponseCode(InviteSendResponse.RESP_NO_INV_AVAILABLE);
			return ret;
		}
		
		// 2. generar hash
		String hash = this.generateInvitation(sqlSession);
		
		// 3. insertar hash en la BBDD
		Date date = new Date();
		this.insertInvitation(sqlSession, email, hash, date, invitingUser);
		
		// 4. preparar los datos del email para el envío
		this.prepareEmailData(sqlSession, invitingUsername, hash, email, ret);
		
		// 5. reducir el contador de invitaciones para el usuario
		availableInvites--;
		this.updateInvitationsCounter(sqlSession, invitingUser, availableInvites);
		
		return ret;
	}
	
	private void updateInvitationsCounter(
			SqlSession sqlSession, 
			int userId, 
			int counterNewValue) {
		
		UsersInviteCountMapper mapper = sqlSession.getMapper(UsersInviteCountMapper.class);
		
		UsersInviteCount usersInviteCount = new UsersInviteCount();
		usersInviteCount.setInvites_counter(counterNewValue);
		usersInviteCount.setUsr_id(userId);
		
		mapper.updateByPrimaryKey(usersInviteCount); 
		
	}
	
	private void prepareEmailData(
			SqlSession sqlSession,
			String username,
			String hash,
			String email,
			InviteSendResponse inviteSendResponse) {
		
		// TODO: Corregir
		Locale locale = new Locale("es", "ES");
		
		String urlTemplate = TextsHelper.getStaticText(
				sqlSession, 
				TextsHelper.TXT_LBL_INV_USR_URL,
				locale.getLanguage());
		
		String emailBodyTemplate = TextsHelper.getStaticText(
				sqlSession, 
				TextsHelper.TXT_LBL_INV_USR_EMAIL_BODY, 
				locale.getLanguage());
		
		String emailSubject = TextsHelper.getStaticText(
				sqlSession, 
				TextsHelper.TXT_LBL_INV_USR_EMAIL_SUBJECT, 
				locale.getLanguage());
		
		String url = MessageFormat.format(urlTemplate, hash);
		String emailBody = MessageFormat.format(emailBodyTemplate, username, url);
		
		inviteSendResponse.setInviteEmailSubject(emailSubject);
		inviteSendResponse.setInviteEmailBody(emailBody);
	}
	
	public int countInvitesForUser(SqlSession sqlSession, int userId) {
		
		int ret = 0;
		
		UsersInviteCountMapper mapper = sqlSession.getMapper(UsersInviteCountMapper.class);
		UsersInviteCountExample example = new UsersInviteCountExample();
		UsersInviteCountExample.Criteria criteria = example.createCriteria();
		criteria.andUsr_idEqualTo(userId);
		
		List<UsersInviteCount> invitesList = mapper.selectByExample(example);
		UsersInviteCount count = null;
		if(invitesList.size() > 0) {
			count = invitesList.get(0);
		}
		
		if(count != null) {
			ret = count.getInvites_counter();
		}
		
		return ret;
		
	}
	
	private String generateInvitation(SqlSession sqlSession) {
		
		String ret = null;
		
		boolean unique = false;
		while(!unique) {

			ret = PasswdHelper.generateHash();

			InvitesSentMapper mapper = sqlSession.getMapper(InvitesSentMapper.class);
			InvitesSentExample example = new InvitesSentExample();
			InvitesSentExample.Criteria criteria = example.createCriteria();
			criteria.andIvs_hashEqualTo(ret);

			int count = mapper.countByExample(example);

			if(count == 0)
				unique = true;

		}

		return ret;
		
	}
	
	private void insertInvitation(
			SqlSession sqlSession, 
			String email, 
			String hash, 
			Date date, 
			int invitingUserId) {
		
		InvitesSentMapper mapper = sqlSession.getMapper(InvitesSentMapper.class);
		InvitesSent invite = new InvitesSent();
		invite.setIvs_date(date);
		invite.setIvs_email(email);
		invite.setIvs_hash(hash);
		invite.setUsr_id(invitingUserId);
		
		mapper.insert(invite);
		
	}
	
	public void deleteInvite(SqlSession sqlSession, String hash) {
		
		InvitesSentMapper mapper = sqlSession.getMapper(InvitesSentMapper.class);
		InvitesSentExample example = new InvitesSentExample();
		InvitesSentExample.Criteria criteria = example.createCriteria();
		criteria.andIvs_hashEqualTo(hash);
		
		mapper.deleteByExample(example);
		
	}
	
}
